#include "SlidingStackedWidget.h"
#include "QTAvkonView.h"

SlidingStackedWidget::SlidingStackedWidget(QWidget *parent) :
	QStackedWidget(parent)
	{
	if (parent != 0)
		{
		m_mainwindow = parent;
		}
	else
		{
		m_mainwindow = this;
		qDebug() << "ATTENTION: untested mainwindow case !";
		}

	m_vertical = false;
	m_speed = 500;
	//check out the QEasingCurve documentation for different styles
	m_animationtype = QEasingCurve::OutBack;
	m_now = 0;
	m_next = 0;
	m_wrap = false;
	m_pnow = QPoint(0, 0);
	m_active = false;
	}

SlidingStackedWidget::~SlidingStackedWidget()
	{
	}

void SlidingStackedWidget::ActivateWidget(const TWidgetId widgetID)
	{
	for (int indx = 0; indx < this->count(); indx++)
		{
		QBaseWidget* basewidget =
				static_cast<QBaseWidget*> (this->widget(indx));
		if (basewidget->Id() == widgetID)
			{
			// set the widget as current widget of the stack
			// activate the new widget

			this->setCurrentWidget(basewidget);
			basewidget->ActivateWidget();
			}
		}

	}

void SlidingStackedWidget::DeActivateWidget(const TWidgetId widgetID)
	{
	QBaseWidget* active_widget =
			static_cast<QBaseWidget*> (this->currentWidget());
	// 0 indicates there are no widgets in the stack
	if ((active_widget != 0) && (active_widget->Id() != widgetID))
		{
		active_widget->DeActivateWidget();
		}
	}

void SlidingStackedWidget::AddWidgetToStack(QWidget* widget)
	{
	this->addWidget(widget);
	}
void SlidingStackedWidget::setVerticalMode(bool vertical)
	{
	m_vertical = vertical;
	}

void SlidingStackedWidget::setSpeed(int speed)
	{
	m_speed = speed;
	}

void SlidingStackedWidget::setAnimation(enum QEasingCurve::Type animationtype)
	{
	m_animationtype = animationtype;
	}

void SlidingStackedWidget::setWrap(bool wrap)
	{
	m_wrap = wrap;
	}

void SlidingStackedWidget::slideInNext()
	{
	int now = currentIndex();
	if (m_wrap || (now < count() - 1))
		// count is inherit from QStackedWidget
		slideInIdx(now, now + 1);
	}

void SlidingStackedWidget::slideInPrev()
	{
	int now = currentIndex();
	if (m_wrap || (now > 0))
		slideInIdx(now, now - 1);
	}

void SlidingStackedWidget::SliderInIdx(int nxt, enum t_direction direction)
	{
	int now = currentIndex();
	slideInIdx(now, nxt);
	}
void SlidingStackedWidget::slideInIdx(int now, int nxt,
		enum t_direction direction)
	{

	/* call activate of the widget which is to be displayed
	 * 
	 */
	//int idx, t_direction direction=AUTOMATIC
	if (now == nxt)
		{
		return;
		}
	if (nxt > count() - 1)
		{
		direction = m_vertical ? TOP2BOTTOM : RIGHT2LEFT;
		nxt = (nxt) % count();
		}
	else if (nxt < 0)
		{
		direction = m_vertical ? BOTTOM2TOP : LEFT2RIGHT;
		nxt = (nxt + count()) % count();
		}

	slideInWgt(now, widget(nxt), direction);
	//widget() is a function inherited from QStackedWidget
	}

void SlidingStackedWidget::slideInWgt(int now, QWidget * newwidget,
		enum t_direction direction)
	{

	if (m_active)
		{
		return; // at the moment, do not allow re-entrance before an animation is completed.
		//other possibility may be to finish the previous animation abrupt, or
		//to revert the previous animation with a counter animation, before going ahead
		//or to revert the previous animation abrupt
		//and all those only, if the newwidget is not the same as that of the previous running animation.
		}
	else
		m_active = true;

	enum t_direction directionhint;
	int next = indexOf(newwidget);
	if (now == next)
		{
		m_active = false;
		return;
		}
	else if (now < next)
		{
		directionhint = m_vertical ? TOP2BOTTOM : RIGHT2LEFT;
		}
	else
		{
		directionhint = m_vertical ? BOTTOM2TOP : LEFT2RIGHT;
		}
	if (direction == AUTOMATIC)
		{
		direction = directionhint;
		}
	//NOW....
	//calculate the shifts

	int offsetx = frameRect().width(); //inherited from mother
	int offsety = frameRect().height();//inherited from mother

	//the following is important, to ensure that the new widget
	//has correct geometry information when sliding in first time
	widget(next)->setGeometry(0, 0, offsetx, offsety);

	if (direction == BOTTOM2TOP)
		{
		offsetx = 0;
		offsety = -offsety;
		}
	else if (direction == TOP2BOTTOM)
		{
		offsetx = 0;
		//offsety=offsety;
		}
	else if (direction == RIGHT2LEFT)
		{
		offsetx = -offsetx;
		offsety = 0;
		}
	else if (direction == LEFT2RIGHT)
		{
		//offsetx=offsetx;
		offsety = 0;
		}
	//re-position the next widget outside/aside of the display area
	QPoint pnext = widget(next)->pos();
	QPoint pnow = widget(now)->pos();
	m_pnow = pnow;

	widget(next)->move(pnext.x() - offsetx, pnext.y() - offsety);
	//make it visible/show
	QBaseWidget* new_widget = static_cast<QBaseWidget*> (newwidget);

	// before starting animation we need to activate the new widget 
	// so that it can create its resources
	ActivateWidget(new_widget->Id());
	widget(now)->show();
	widget(next)->raise();

	//animate both, the now and next widget to the side, using animation framework
	QPropertyAnimation *animnow = new QPropertyAnimation(widget(now), "pos");

	animnow->setDuration(m_speed);
	animnow->setEasingCurve(m_animationtype);
	animnow->setStartValue(QPoint(pnow.x(), pnow.y()));
	animnow->setEndValue(QPoint(offsetx + pnow.x(), offsety + pnow.y()));
	QPropertyAnimation *animnext = new QPropertyAnimation(widget(next), "pos");
	animnext->setDuration(m_speed);
	animnext->setEasingCurve(m_animationtype);
	animnext->setStartValue(QPoint(-offsetx + pnext.x(), offsety + pnext.y()));
	animnext->setEndValue(QPoint(pnext.x(), pnext.y()));

	QParallelAnimationGroup *animgroup = new QParallelAnimationGroup;

	animgroup->addAnimation(animnow);
	animgroup->addAnimation(animnext);

	QObject::connect(animgroup, SIGNAL(finished()), this,
			SLOT(animationDoneSlot()));

	m_next = next;
	m_now = now;
	m_active = true;
	animgroup->start();

	//note; the rest is done via a connect from the animation ready;
	//animation->finished() provides a signal when animation is done;
	//so we connect this to some post processing slot,
	//that we implement here below in animationDoneSlot.
	}

void SlidingStackedWidget::animationDoneSlot(void)
	{
	//when ready, call the QStackedWidget slot setCurrentIndex(int)
	setCurrentIndex(m_next); //this function is inherit from QStackedWidget
	//then hide the outshifted widget now, and  (may be done already implicitely by QStackedWidget)
	widget(m_now)->hide();
	QBaseWidget* del_widget = static_cast<QBaseWidget*> (widget(m_now));

	// once animation is done we can deactivate the widget
	// so that it can release all its resources
	del_widget->DeActivateWidget();

	//then set the position of the outshifted widget now back to its original
	widget(m_now)->move(m_pnow);
	//so that the application could also still call the QStackedWidget original functions/slots for changings
	//widget(m_now)->update();
	//setCurrentIndex(m_next);  //this function is inherit from QStackedWidget
	m_active = false;
	QTAvkonView* main_widget = static_cast<QTAvkonView*> (m_mainwindow);
	main_widget->listAll->setCurrentIndex(m_next);
	emit animationFinished();
	}

bool SlidingStackedWidget::getVerticalMode()
	{
	return m_vertical;
	}
